#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libubox/usock.h>
#include <libubox/uloop.h>


static void read_server(struct uloop_fd *u, unsigned int events);
static void read_std(struct uloop_fd *u, unsigned int events);

char send_buf[1024];
int client_fd = 0;
struct uloop_timeout timeout;

#define DM_SERVER_HOST "127.0.0.1"
#define DM_SERVER_PORT "8888"

typedef enum {
	STD_IO_FD = 0,
	DM_SERVER_FD = 1,

	MAX_FD = 2
}fd_type_t;

struct uloop_fd g_fd[MAX_FD];

void conncet_server(struct uloop_timeout *t) {
    int type = USOCK_TCP | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;

    printf("conncet_server\n");

    if (g_fd[DM_SERVER_FD].registered) {
        printf("Error: have register server fd\n");

    	return ;
    }

	client_fd = usock(type, DM_SERVER_HOST, DM_SERVER_PORT);
	if (client_fd < 0) {
		printf("Failed to connet to server!!!\n");

	    timeout.cb = conncet_server;
	    uloop_timeout_set(&timeout, 2000);

	    return ;
	}

    printf("add loop\n");

    g_fd[DM_SERVER_FD].cb = read_server;
    g_fd[DM_SERVER_FD].fd = client_fd;

    uloop_fd_add(&g_fd[DM_SERVER_FD], ULOOP_READ|ULOOP_WRITE|ULOOP_EDGE_TRIGGER|ULOOP_BLOCKING|ULOOP_ERROR_CB);

    printf("server socket &g_fd[0]->eof=%d,u->error=%d,u->fd=%d,u->flags=%d,u->registered=%d \n",
    		g_fd[DM_SERVER_FD].eof,g_fd[DM_SERVER_FD].error,g_fd[DM_SERVER_FD].fd,g_fd[DM_SERVER_FD].flags,g_fd[DM_SERVER_FD].registered);

    return ;
}


static void read_server(struct uloop_fd *u, unsigned int events)
{
    char buf[1024] = {0};

    printf("server socket events=%d, u->eof=%d, u->error=%d, u->fd=%d, u->flags=%d, u->registered=%d\n",
    		events, u->eof,u->error,u->fd,u->flags,u->registered);

    if (u->error || u->eof) {
    	printf("The socket of conncet server is error!!!\n");

    	close(u->fd);

    	uloop_fd_delete(u);

        printf("server socket &g_fd[0]->eof=%d,u->error=%d,u->fd=%d,u->flags=%d,u->registered=%d \n",
        		g_fd[DM_SERVER_FD].eof,g_fd[DM_SERVER_FD].error,g_fd[DM_SERVER_FD].fd,g_fd[DM_SERVER_FD].flags,g_fd[DM_SERVER_FD].registered);

    	conncet_server(NULL);

    	return ;
    }

    if (events & ULOOP_READ) {
        if ( recv(u->fd, buf, 1024, 0) > 0) {
            printf("from client recv_buf: %s\n", buf);
        }
    }
}

static void read_std(struct uloop_fd *u, unsigned int events)
{
	send_buf[0] = '\0';
	int ret = 0;

    printf("read_std\n");
	if (events & ULOOP_READ) {
        if (read(u->fd, send_buf, 1024) > 0) {
            printf("from stdin read_std: %s\n", send_buf);

            ret = send(client_fd, send_buf, strlen(send_buf), 0);
        	printf("ret = %d\n", ret);

            if (ret < 0) {
            	printf("Failed to send to server!!!\n");

            	return ;
            }
        }
    }
}

int main()
{
	uloop_init();

    g_fd[STD_IO_FD].cb = read_std;
    g_fd[STD_IO_FD].fd = STDIN_FILENO;
    uloop_fd_add(&g_fd[STD_IO_FD], ULOOP_READ);

	conncet_server(NULL);

	uloop_run();

	uloop_done();

	close(client_fd);

	return 0;
}
